

#include "http_conn.h"

int HttpConn::m_epollfd = -1;
uint HttpConn::m_user_count = 0;

void setnonblocking(int fd) {
    // 设置文件描述符非阻塞
    int old_flag = fcntl(fd, F_GETFL);
    int new_flg = old_flag | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_flg);
}

// 向epoll中添加需要监听的文件描述符
void addfd(int epollfd, int fd, bool one_shot) {
    epoll_event event;
    event.data.fd = fd;
    event.events =
        EPOLLIN | EPOLLRDHUP;  // EPOLLRDHUP 对方连接断开时触发epollin

    if (one_shot) {
        event.events |= EPOLLONESHOT;
    }
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
    // 设置文件描述符非阻塞
    setnonblocking(fd);
}

void removefd(int epollfd, int fd) {
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, 0);
    close(fd);
}

// 修改文件描述符， 注意重置socket上的epolloneshot事件
// 确保下一次可读时，epollin事件能被触发
void modfd(int epollfd, int fd, int ev) {
    epoll_event event;
    event.data.fd = fd;
    event.events = ev | EPOLLRDHUP | EPOLLONESHOT;
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
}

// 初始化连接
void HttpConn::init(int sockfd, const sockaddr_in& addr) {
    m_socketfd = sockfd;
    m_address = addr;

    // 设置端口复用
    int reuse = 1;
    setsockopt(m_socketfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

    // 添加到epoll对象中
    addfd(m_epollfd, m_socketfd, true);
    m_user_count++;  // 总用户数+1

    init();
}


void HttpConn::init(){
    m_check_state = CHECK_STATE_REQUESTLINE; // 初始化状态为解析请求首行
    m_checked_idx = 0;
    m_start_line = 0;
    m_read_idx = 0;
    m_metod = GET;
    m_url = 0;
    m_version = 0;
    m_host = 0; 
    m_linger = false;

    bzero(m_read_buf, READ_BUFFER_SIZE);
}

// 关闭连接
void HttpConn::close_conn() {
    if (m_socketfd != -1) {
        removefd(m_epollfd, m_socketfd);
        m_socketfd = -1;  // 置为-1之后该fd就没有用了
        m_user_count--;
    }
}

// 循环读取数据，直到对方断开连接或者无数据可读
bool HttpConn::read() {
    if (m_read_idx >= READ_BUFFER_SIZE) {
        // 缓冲区已满，下一次在读
        return false;
    }

    // 已经读取到的字节
    int bytes_read = 0;
    while (true) {
        bytes_read = recv(m_socketfd, m_read_buf + m_read_idx,
                          READ_BUFFER_SIZE - m_read_idx, 0);
        if (bytes_read == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 非阻塞的读 没有数据了
                break;
            }
            return false;
        } else if (bytes_read == 0) {
            // 对方关闭连接
            return false;
        }

        m_read_idx += bytes_read;
    }

    printf("读取到了数据 ： %s\n", m_read_buf);
    return true;
}

// 主状态机  解析HTTP请求
HttpConn::HTTP_CODE HttpConn::process_read() {
    
    LINE_STATUS line_status = LINE_OK;
    HTTP_CODE ret = NO_REQUEST;

    char *text = 0;
    while(((m_check_state == CHECK_STATE_CONTENT) && (line_status == LINE_OK))
     || (line_status = parse_line()) == LINE_OK){
        // 解析到了一行完整的饿数据，或者解析到了请求体也是完整的数据

        // 获取一行数据
        text = get_line();

        m_start_line = m_checked_idx;
        printf("got 1 http line : %s\n", text);

        switch(m_check_state){ 
            case CHECK_STATE_REQUESTLINE:{
                ret = parse_request_line(text);
                if (ret == BAD_REQUEST){
                    return BAD_REQUEST;
                }
                break;
            }

            case CHECK_STATE_HEADER:{
                ret = parse_headers(text);
                if ( ret == BAD_REQUEST){
                    return BAD_REQUEST;
                }else if (ret == GET_REQUEST){
                    return do_request();
                }
                break;
            }
            
            case CHECK_STATE_CONTENT:{
                ret = parse_content(text);
                if (ret == GET_REQUEST){
                    return do_request();
                }
                line_status = LINE_OPEN;
                break;
            }

            default:{
                return INTERNAL_ERROR;
            }
        }

        return NO_REQUEST;
    }

    return NO_REQUEST;
}

// 解析请求行 获取请求方法， 目标URL， HTTP版本
HttpConn::HTTP_CODE HttpConn::parse_request_line(char* text) {
    // GET /index.html HTTP/1.1
    m_url = strpbrk(text, " \t"); // 字符串的第一个匹配到的位置
    // GET\0/index.html HTTP/1.1
    *m_url++ = '\0';
    char * method = text;
    if (strcasecmp(method, "GET") == 0){ // 忽略大小写的比较
        m_metod = GET;
    }else {
        return BAD_REQUEST;
    }
    // /index.html HTTP/1.1
    m_version = strpbrk(m_url, " \t");
    if(!m_version){
        return BAD_REQUEST;
    }
    *m_version++ = '\0';
    if (strcasecmp(m_version, "HTTP/1.1") !=0){
        return BAD_REQUEST;
    }
    // http://192.168.1.24:9999/index.html
    if (strncasecmp(m_url, "http://", 7) == 0){
        m_url += 7;
        // 192.168.1.24:9999/index.html
        m_url = strchr(m_url, '/'); // 找斜线第一次出现的位置
    }
    if (!m_url || m_url[0] != '/'){
        return BAD_REQUEST;
    }

    m_check_state = CHECK_STATE_HEADER; // 主状态机检查状态变成检查请求头
    
    return NO_REQUEST;
}

// 解析请求头
HttpConn::HTTP_CODE HttpConn::parse_headers(char* text) {
    return NO_REQUEST;
}

// 解析请求体
HttpConn::HTTP_CODE HttpConn::parse_content(char* text) {
    return NO_REQUEST;
}

// 解析一行, 判断依据 \r\n
HttpConn::LINE_STATUS HttpConn::parse_line() {
    char temp;
    for(;m_checked_idx < m_read_idx; ++m_checked_idx){
        temp = m_read_buf[m_checked_idx];
        if(temp == '\r'){
            if( (m_checked_idx + 1) == m_read_idx){
                return LINE_OPEN; // 不完整数据 
            }else if(m_read_buf[m_checked_idx + 1] == '\n'){
                m_read_buf[m_checked_idx++] = '\0';
                m_read_buf[m_checked_idx++] = '\0';
                // 完整的解析到了一行
                return LINE_OK;
            }
            return LINE_BAD;
        }else if(temp == '\n'){
            if((m_checked_idx > 1) && (m_read_buf[m_checked_idx - 1] == '\r')){
                m_read_buf[m_checked_idx - 1] = '\0';
                m_read_buf[m_checked_idx++] = '\0';
                return LINE_OK;
            }
        }
        return LINE_OPEN;
    }


}


HttpConn::HTTP_CODE HttpConn::do_request() {

}




bool HttpConn::write() {
    printf("一次性写完数据\n");
    return true;
}

// 由线程池中的工作线程调用， 处理HTTP请求的入口函数
void HttpConn::process() {
    // 解析HTTP请求

    HTTP_CODE read_ret = process_read();
    if (read_ret == NO_REQUEST == NO_REQUEST) {
        modfd(m_epollfd, m_socketfd, EPOLLIN);
        return;
    }

    printf("parse request , create response\n");

    // 生成响应
}
